package panic_recover

import "fmt"

/** panic 和 recover

什么是 panic？
在 Go 语言中，程序中一般是使用错误[2]来处理异常情况。对于程序中出现的大部分异常情况，错误就已经够用了。

但在有些情况，当程序发生异常时，无法继续运行。在这种情况下，我们会使用 panic 来终止程序。

在本教程里，我们还会接着讨论，当程序发生 panic 时，使用 recover 可以重新获得对该程序的控制。

可以认为 panic 和 recover 与其他语言中的 try-catch-finally 语句类似，
只不过一般我们很少使用 panic 和 recover。而当我们使用了 panic 和 recover 时，
也会比 try-catch-finally 更加优雅，代码更加整洁。
*/

/*
panic 示例

	func panic(interface{})
*/
func Test() {

	// 示例1
	//case1()

	// 示例2
	case2()
}

// 示例1
func case1() {
	defer fmt.Println("deferred call in main")
	userName := "lili"
	checkName(&userName, nil)

}

func checkName(userName *string, nickName *string) {
	defer fmt.Println("deferred call in fullName") //当出现panic，会先执行defer

	if userName == nil {
		panic("userName is nil")
	}
	if nickName == nil {
		panic("nickName is nil")
	}
	fmt.Printf("%s %s \n", *userName, *nickName)
	fmt.Println("checkName end...")
}

// recover 函数的标签如下所示：
// func recover() interface{}
func case2() {
	defer fmt.Println("deferred call in main")
	firstName := "Elon"
	fullName(&firstName, nil)
	fmt.Println("returned normally from main")
}

func recoverName() {
	if r := recover(); r != nil {
		fmt.Println("recoverName() ", r)
	}
}

func fullName(firstName *string, lastName *string) {
	defer recoverName()
	if firstName == nil {
		panic("firstName is nil")
	}
	if lastName == nil {
		panic("lastName is nil")
	}
	fmt.Printf("%s %s\n", *firstName, *lastName)
	fmt.Println("fullName() end ...")
}
